/*
 * Copyright (C) 2017 grandcentrix GmbH
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.grandcentrix.thirtyinch;

import net.grandcentrix.thirtyinch.internal.*;
import ohos.aafwk.ability.LifecycleObserver;
import ohos.aafwk.ability.fraction.FractionAbility;
import ohos.aafwk.content.Intent;
//import androidx.annotation.CallSuper;
import ohos.bundle.AbilityInfo;
import ohos.utils.PacMap;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Executor;

import net.grandcentrix.thirtyinch.util.AnnotationUtil;

/**
 * An Activity which has a {@link TiPresenter} to build the Model View Presenter architecture on
 * Android.
 *
 * <p>
 * The {@link TiPresenter} will be created in {@link #providePresenter()} called in
 * {@link #onStart(Intent)}. Depending on the {@link TiConfiguration} passed into the
 * {@link TiPresenter#TiPresenter(TiConfiguration)} constructor the {@link TiPresenter} survives
 * orientation changes (default).
 * </p>
 * <p>
 * The {@link TiPresenter} requires a interface to communicate with the View. Normally the Activity
 * implements the View interface (which must extend {@link TiView}) and is returned by default
 * from {@link #provideView()}.
 * </p>
 *
 * <p>
 * Example:
 * <code>
 * <pre>
 * public class MyActivity extends TiActivity&lt;MyPresenter, MyView&gt; implements MyView {
 *
 *     &#064;Override
 *     public MyPresenter providePresenter() {
 *         return new MyPresenter();
 *     }
 * }
 *
 * public class MyPresenter extends TiPresenter&lt;MyView&gt; {
 *
 *     &#064;Override
 *     protected void onCreate() {
 *         super.onCreate();
 *     }
 * }
 *
 * public interface MyView extends TiView {
 *
 *     // void showItems(List&lt;Item&gt; items);
 *
 *     // Observable&lt;Item&gt; onItemClicked();
 * }
 * </pre>
 * </code>
 * </p>
 *
 * @param <V> the View type, must implement {@link TiView}
 * @param <P> the Presenter type, must extend {@link TiPresenter}
 */
public abstract class TiActivity<P extends TiPresenter<V>, V extends TiView>
        extends FractionAbility
        implements TiPresenterProvider<P>, TiViewProvider<V>, DelegatedTiActivity,
        TiLoggingTagProvider, InterceptableViewBinder<V>, PresenterAccessor<P, V> {

    private final String TAG = this.getClass().getSimpleName()
            + ":" + TiActivity.class.getSimpleName()
            + "@" + Integer.toHexString(this.hashCode());

    private final TiActivityDelegate<P, V> mDelegate
            = new TiActivityDelegate<>(this, this, this, this, PresenterSavior.getInstance());

    private final UiThreadExecutor mUiThreadExecutor = new UiThreadExecutor();

    ArrayList<ILifecycleObserver> mLifecycleObserverList = new ArrayList<>();

    public void addAdvancedLifecycle(ILifecycleObserver observer){
        getLifecycle().addObserver(observer.getLifecycleObserver());
        mLifecycleObserverList.add(observer);
    }

    public void removeAdvancedLifecycle(ILifecycleObserver observer){
        getLifecycle().removeObserver(observer.getLifecycleObserver());
        mLifecycleObserverList.remove(observer);

    }

    @Override
    protected void onPostStart(PacMap map) {
        super.onPostStart(map);
        TiLog.d("Life", "onPostStart");
        mLifecycleObserverList.forEach(observer->observer.onActivityCreated(this, map));
        mDelegate.onCreate_afterSuper(map);
        mDelegate.onStart_afterSuper(); // onForeground 在首次创建的时候不会被调用
    }

    //@CallSuper
    @Override
    protected void onForeground(Intent intent) {
        super.onForeground(intent);
        mDelegate.onStart_afterSuper();
    }

    //@CallSuper
    @Override
    protected void onBackground() {
        mDelegate.onStop_beforeSuper();
        super.onBackground();
        mDelegate.onStop_afterSuper();
    }

    //@CallSuper
    @Override
    public void onSaveAbilityState(@NotNull final PacMap outState) {
        super.onSaveAbilityState(outState);
        mDelegate.onSaveInstanceState_afterSuper(outState);
        mLifecycleObserverList.forEach(iLifecycleObserver -> iLifecycleObserver.onActivitySaveInstanceState(this, outState));
    }

    //@CallSuper
    @Override
    protected void onStop() {
        super.onStop();
        mDelegate.onDestroy_afterSuper();
    }

    @NotNull
    @Override
    public final Removable addBindViewInterceptor(@NotNull final BindViewInterceptor interceptor) {
        return mDelegate.addBindViewInterceptor(interceptor);
    }

    @Override
    public final Object getHostingContainer() {
        return this;
    }

    @Nullable
    @Override
    public final V getInterceptedViewOf(@NotNull final BindViewInterceptor interceptor) {
        return mDelegate.getInterceptedViewOf(interceptor);
    }

    @NotNull
    @Override
    public final List<BindViewInterceptor> getInterceptors(
            @NotNull final Filter<BindViewInterceptor> predicate) {
        return mDelegate.getInterceptors(predicate);
    }

    @Override
    public String getLoggingTag() {
        return TAG;
    }

    /**
     * is {@code null} before {@link #onStart(Intent)}
     */
    @Override
    public final P getPresenter() {
        return mDelegate.getPresenter();
    }

    @Override
    public final Executor getUiThreadExecutor() {
        return mUiThreadExecutor;
    }

    /**
     * Invalidates the cache of the latest bound view. Forces the next binding of the view to run
     * through all the interceptors (again).
     */
    @Override
    public final void invalidateView() {
        mDelegate.invalidateView();
    }

    @Override
    public final boolean isActivityFinishing() {
        return isTerminating();
    }

    //@CallSuper
    @Override
    public void onOrientationChanged(@NotNull final AbilityInfo.DisplayOrientation displayOrientation) {
        super.onOrientationChanged(displayOrientation);
        mDelegate.onConfigurationChanged_afterSuper(displayOrientation);
    }

    @SuppressWarnings("unchecked")
    @NotNull
    @Override
    public V provideView() {
        final Class<?> foundViewInterface = AnnotationUtil
                .getInterfaceOfClassExtendingGivenInterface(this.getClass(), TiView.class);

        if (foundViewInterface == null) {
            throw new IllegalArgumentException(
                    "This Activity doesn't implement a TiView interface. "
                            + "This is the default behaviour. Override provideView() to explicitly change this.");
        } else {
            if (foundViewInterface.getSimpleName().equals("TiView")) {
                throw new IllegalArgumentException(
                        "extending TiView doesn't make sense, it's an empty interface."
                                + " This is the default behaviour. Override provideView() to explicitly change this.");
            } else {
                // assume that the activity itself is the view and implements the TiView interface
                return (V) this;
            }
        }
    }

    @Override
    public String toString() {
        String presenter = mDelegate.getPresenter() == null ? "null" :
                mDelegate.getPresenter().getClass().getSimpleName()
                        + "@" + Integer.toHexString(mDelegate.getPresenter().hashCode());

        return getClass().getSimpleName()
                + ":" + TiActivity.class.getSimpleName()
                + "@" + Integer.toHexString(hashCode())
                + "{presenter = " + presenter + "}";
    }


}
